package com.qhx.rtkcloud.tcp;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

@Component
@Profile({"ntripclient"})
public class NtripClientExchangePair extends NtripExchangePair {



    public NtripClientExchangePair() throws IOException {
        super();
    }


//    private Pair<String, Integer> getIpAndPort(String ipAndPort) {
//        int colon = ipAndPort.indexOf(":");
//        if (colon == -1 && ipAndPort.matches("-?\\d+(\\.\\d+)?")) { // 只有端口
//            return new Pair<>("127.0.0.1", Integer.parseInt(ipAndPort));
//        }
//
//        if (colon > 0) {
//            String ip = ipAndPort.substring(0, colon);
//            int port = Integer.parseInt(ipAndPort.substring(colon + 1));
//            return new Pair<>(ip, port);
//        }
//        return null;
//    }

    private static final String clientAuth = "GET /${mount} HTTP/1.0\nUser-Agent: NTRIP GNSSInternetRadio/1.4.10\n"
            + "Accept: */*\n"
            + " Connection: close\n";

    private static final String clientAuthTwo ="SOURCE letmein /${mount}\n" +
            "Source-Agent: NTRIP NtripServerCMD/1.0\n\n";

    private String[] getMountAndUserName(String rawMount) {
        int and = rawMount.indexOf("&");
        if (and == -1) {
            return new String[]{rawMount, null};
        }

        return new String[]{rawMount.substring(0, and), rawMount.substring(and + 1)};
    }

    private String encodeBase64(String msg) {
        return new String(Base64Utils.encode(msg.getBytes()));
    }

    private String getUsername(String usernameAndPwd) {
        if (usernameAndPwd == null || usernameAndPwd.length() == 0) {
            return null;
        }

        int colon = usernameAndPwd.indexOf(":");

        if (colon <= 0) {
            return null;
        }

        return usernameAndPwd.substring(0, colon);

    }

    private TcpExchangeUnit getTcpExchangeUnit(String mount, String username) {
        if (username == null) {
            return super.getNtripExchangeUnitMap().get(mount);
        }
        return super.getNtripExchangeUnitMap().get(mount + "&" + username);
    }

    private boolean readAuthAnswer(InputStream inputStream) {
        byte[] bytes = new byte[10240];
        int length = 0;
        try {
            if ((length = inputStream.read(bytes)) > 0) {
                String answer = new String(Arrays.copyOfRange(bytes, 0, length));
                return true;
                //            if (answer.startsWith("ICY 200 OK")) {
                //                return true;
                //            }
            }
        } catch (IOException e) {
            return false;
        }
        return false;
    }

    private void  processAfterAuth(Socket socket, TcpExchangeUnit tcpExchangeUnit) {
        if (tcpExchangeUnit == null) {
            try {
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            return;
        }
        if ((!tcpExchangeUnit.isConnectFreedom() && (tcpExchangeUnit.getPartner().getClient() == null || tcpExchangeUnit.getPartner().getClient().isClosed()))) {
            try {
                socket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

             throw  new RuntimeException();
        }
        if (tcpExchangeUnit.isConnectFreedom() && !tcpExchangeUnit.getPartner().isConnectFreedom()
                &&(tcpExchangeUnit.getPartner().getClient()!=null && tcpExchangeUnit.getPartner().getClient().isConnected()) ){
            try {
                if(tcpExchangeUnit.getPartner().getClient() != null) {
                    tcpExchangeUnit.getPartner().getClient().close();

                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
            TcpExchangeUnit tcpExchangeUnit1 =   TcpExchangeUnit.TCP_EXCHANGE_UNIT_THREAD_LOCAL.get();
            String message = e.getMessage();
            if (message != null) {
                String[] params = message.split(":");

                if (tcpExchangeUnit1 == null) {
                    return;
                }
                if (tcpExchangeUnit1.isConnectFreedom() && !tcpExchangeUnit1.getPartner().isConnectFreedom() && tcpExchangeUnit1.getClient() != null) {
                    try {
                        tcpExchangeUnit1.getPartner().getClient().close();
                    } catch (IOException ex) {
                        throw new RuntimeException(ex);
                    }
                }
                TcpExchangeUnit.TCP_EXCHANGE_UNIT_THREAD_LOCAL.remove();
                if (params.length == 3) {
                     connectServer(tcpExchangeUnit1, params[1], Integer.valueOf(params[2]));
                }
            }

        });

        tcpExchangeUnit.setClient(socket);
        tcpExchangeUnit.start();
    }

    private void doConnectServer( TcpExchangeUnit tcpExchangeUnit, String host, int port, String authInfo) {

        Socket socket = null;
        InputStream inputStream = null;
        try {
            socket = new Socket(host, port);
            OutputStream outputStream = socket.getOutputStream();
            inputStream = socket.getInputStream();
            outputStream.write(authInfo.getBytes());
            outputStream.flush();
        } catch (IOException e) {
            doConnectServer(tcpExchangeUnit, host, port, authInfo);
        }

        if (readAuthAnswer(inputStream)) {
            try {
                processAfterAuth(socket, tcpExchangeUnit);
            } catch (RuntimeException e) {
                doConnectServer(tcpExchangeUnit, host, port, authInfo);
                e.printStackTrace();
            }

        }
    }

    private String getAuthInfo(String mount, String username, int authType) {
        String authInfo = "";
        if (authType == 1) {
            authInfo =  clientAuth.replace("${mount}", mount);
        } else {
            authInfo = clientAuthTwo.replace("${mount}", mount);
        }

        if (username != null) {
            authInfo = authInfo + "Authorization: Basic " + encodeBase64(username) + "\n";
        }
        authInfo = authInfo + "\n";
        return authInfo;
    }



    public void connectServer(TcpExchangeUnit tcpExchangeUnit, String host, int port) {
        synchronized (tcpExchangeUnit.isConnectFreedom() ? tcpExchangeUnit.connectLock : tcpExchangeUnit.getPartner().connectLock) {
            String[]  pair =  getMountAndUserName(tcpExchangeUnit.getMount());
            doConnectServer(tcpExchangeUnit, host, port, getAuthInfo(pair[0], pair[1], tcpExchangeUnit.getAuthType())); // 需要加用户名密码
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        super.afterPropertiesSet();


    }
}
